home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / Thread Manager / ThreadUtilities / SnakesWithSemaphores / ThreadedSnakes.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-17  |  9.6 KB  |  289 lines  |  [TEXT/MPS ]

  1. /*
  2.  *  ThreadedSnakes.c
  3.  *
  4.  *  Author:  Brad Post
  5.  *    Creation Date:    12/16/92
  6.  *  Copyright  © 1992, 1993  Apple Computer Inc.
  7.  *
  8.  *    This file contains all the drawing routines for the snakes, as well as the initialization and 
  9.  *  cleanup routines.
  10.  *  A special thanks goes out to David Anderson my Operating Systems Professor at Berkeley.  His excellent
  11.  *  teachings helped me learn semaphores and light-weigth processes.  I based this code on one of my programming
  12.  *  assignment in his class.
  13.  */
  14.  
  15. #include "ThreadedSnakes.h"
  16.  
  17. /*
  18.  *  To choose which semaphore model to use, make any of the following equal to 1.  To see some interesting side
  19.  *  effects, as described in drawSnake, make all of them 0.
  20.  */
  21.  
  22. #define SIMPLESNAKES    0
  23. #define LLSNAKES        1
  24. #define ARRAYSNAKES        0
  25.  
  26. #define areaSize    25
  27.  
  28. /*  The snakes that we are going to run with. */
  29.  
  30. SNAKE_ARGS    snake1 = { {200, 50}, {2, 1}, 20, 350, kPreemptiveThread, { 0xDD6b, 0x8C2, 0x6a2 } };
  31. SNAKE_ARGS    snake2 = { {10, 20}, {2, 1}, 20, 350, kPreemptiveThread, { 0, 0, 0xd400 } };
  32. SNAKE_ARGS    snake3 = { {10, 100}, {2, 1}, 20, 350, kPreemptiveThread, { 0, 0, 0 } };
  33. SNAKE_ARGS    snake4 = { {10, 260}, {2, 1}, 20, 350, kPreemptiveThread, { 0, 0x8000, 0x11b0 } };
  34. SNAKE_ARGS    snake5 = { {260, 10}, {2, 1}, 20, 350, kPreemptiveThread, { 0x23c8, 0xfb1e, 0xffff } };
  35.  
  36. /* Declare our semaphore as a global */
  37.  
  38. #if LLSNAKES
  39.     LinkedListSemaphorePtr    theLLSemaphore;
  40. #elif SIMPLESNAKES
  41.     SimpleSemaphorePtr     theSimpleSemaphore;
  42. #elif ARRAYSNAKES
  43.     ArraySemaphorePtr        theArraySemaphore;
  44. #endif
  45.  
  46. /* 
  47.  *    cleanUpSnakes
  48.  *    
  49.  *  INPUT:    void
  50.  *  RETURN:    void
  51.  *
  52.  *  This function is called when we quit, and all it does is dispose of the semaphore by
  53.  *  making the call to the proper function.  The code is ugly, because I hack around my checks to 
  54.  *  see if anyone is waiting on the semaphore.  By making the waitingList = NULL in LinkedList
  55.  *  semaphores, we can then delete it.  Also if you set the numberWaiting = 0 when using ArraySemaphores
  56.  *  you can delete them too.
  57.  */
  58. void cleanUpSnakes()
  59. {
  60.     ThreadBeginCritical();
  61. #if LLSNAKES
  62.     if(DeleteLinkedListSemaphore( theLLSemaphore) != noErr)
  63.     {
  64.         theLLSemaphore->theHolder = kNoThreadID;
  65.         theLLSemaphore->waitingList = NULL;
  66.         
  67.         if(DeleteLinkedListSemaphore( theLLSemaphore) != noErr)
  68.             DebugStr("\pFailed to delete the LinkedList Semaphore");
  69.     }
  70. #elif SIMPLESNAKES
  71.     if(DeleteSimpleSemaphore( theSimpleSemaphore ) != noErr)
  72.         DebugStr("\pFailed to delete the Simple Semaphore");
  73. #elif ARRAYSNAKES
  74.     if( DeleteArraySemaphore( theArraySemaphore ) != noErr)
  75.     {
  76.         theArraySemaphore->numberWaiting = 0;
  77.         if( DeleteArraySemaphore( theArraySemaphore ) != noErr)
  78.             DebugStr("\pFailed to delete the Array Semaphore");
  79.     }
  80. #endif
  81.     ThreadEndCritical();
  82.     
  83.     ExitToShell();
  84. }
  85.  
  86. /*
  87.  *    snakeMover
  88.  *    
  89.  *  INPUT:    VEC, VEC
  90.  *  RETURN:    void
  91.  *
  92.  *  This function calculates the next position for the snake to move to.  Depends on the velocity
  93.  *  of the snake.
  94.  */
  95. snakeMover(VEC position, VEC velocity)
  96. {
  97.     short i;
  98.         
  99.     for(i = 0; i < 2; i++)
  100.     {
  101.         position[i] += velocity[i];
  102.         if((position[i] < 0) || ( (position[i] + 45) >= theBounds[i]))
  103.         {
  104.             velocity[i] = -velocity[i];
  105.             position[i] += 2 * velocity[i];
  106.         }
  107.     }
  108. }
  109.         
  110. /*
  111.  *    drawSnake
  112.  *    
  113.  *  INPUT:    void *
  114.  *  RETURN:    void
  115.  *
  116.  *  This routing draws the snake.  We either draw a RECTANGLE for COOPERATIVE threads, or an OVAL for
  117.  *  PREEMPTIVE threads.  The color is determined by the snake characteristics.  Now every thread calls this
  118.  *  routine, wether it's preemptive or not, and if you are running without semaphores, you see some ugly
  119.  *  side effects.
  120.  *  Now when you are running these with a semaphore model, you will see some of the snakes get drawn over.
  121.  *  This is because I didn't wish to make all the necessary calculations to see what type of snake, and
  122.  *  what color I am drawing over, and correctly draw the background color.
  123.  *
  124.  *  NOTE:   LOTS of ILLEGAL things are going on in this function during PREEMPTIVE THREAD execution.
  125.  *            DON'T TRY THIS AT HOME!!!!  (Though I doubt you'll listen... :-)
  126.  *  SIDE EFFECTS:  Since quickdraw is partially/kinda-sorta/re-entrant, we can, but don't quote me on this, call 
  127.  *      this function during preemptive times.  But we have some interesting side effects.  To see them, make sure
  128.  *      you haven't selected any Semaphore model above, and you'll notice bars of colors starting to appear
  129.  *         on the screen as the snakes draw themselves.  This is because the snakes are being interrupted and
  130.  *        Quickdraw is changing colors on the fly.  You don't get this with the semaphore model, because every
  131.  *        snake needs to own the semaphore before it can draw, guarenteeing that it won't be interrupted and 
  132.  *        Quickdraw won't change colors.
  133.  *        Also, if you are using the semaphore model, you might notice that the Preemptive threads appear to be
  134.  *        going slower.  This is only because we are drawing an OVAL instead of a RECTANGLE.
  135.  */
  136. pascal void *drawSnake(void *aSnake)
  137. {
  138.     SNAKE_ARGS             *theSnake = (SNAKE_ARGS *) aSnake;    // the snake we are going to draw
  139.     VEC                 elements[20] = { 0 };                // draw only 20 links of the snake then start erasing
  140.     short                 index,                                // index into elements
  141.                         count;                                // count the number of moves we've made
  142.     Rect                rect;                                // rectangle to bounds either the OVAL or RECT we draw
  143.     LinkedListElement    iAmWaiting;                            // only used if using linkedlist semaphores
  144.         
  145.     for( ;; )  // loop forever
  146.     {
  147.         /* 
  148.          * Depending on the semaphore we are using, call the right function to get
  149.          * the semaphore.
  150.          */
  151. #if LLSNAKES
  152.         GetLinkedListSemaphore(&iAmWaiting, theLLSemaphore);
  153. #elif SIMPLESNAKES
  154.         GetSimpleSemaphore( theSimpleSemaphore );
  155. #elif ARRAYSNAKES
  156.         GetArraySemaphore( theArraySemaphore );
  157. #endif
  158.  
  159.         // move the snakes for theSnake->numOfMoves until we release the semaphore
  160.         for(count = 0; count < theSnake->numOfMoves; count++)            
  161.         {                                            
  162.             index = count % theSnake->length;            // which segement are we on
  163.             
  164.             snakeMover(theSnake->pos, theSnake->vel);    // where is the segment moving to?
  165.             
  166.             rect.left = elements[index][1];                // segements coordinates
  167.             rect.top = elements[index][0];
  168.             rect.bottom = rect.top + areaSize;
  169.             rect.right = rect.left + areaSize;
  170.             
  171.             MoveTo(elements[index][1], elements[index][0]);        // move to top, left corner of segement
  172.             
  173.             PenMode(patBic);                // we are going to erase the segment                    
  174.             
  175.             RGBForeColor(&(theSnake->whatColor));
  176.             if(theSnake->whatStyle == kCooperativeThread)
  177.                 PaintRect(&rect);                    // Draw a rectangle, symbolizing we are Cooperative
  178.             else
  179.                 PaintOval(&rect);                    // Draw an oval, symbolizing we are Preemptive
  180.                 
  181.             PenMode(patCopy);                // going to draw the new segment
  182.                     
  183.             elements[index][0] = theSnake->pos[0];    // set up for the new segment
  184.             elements[index][1] = theSnake->pos[1];
  185.             
  186.             MoveTo(elements[index][1], elements[index][0]);        // move to the top, left corner of segment
  187.             
  188.             rect.left = elements[index][1];        // set up the rect of the segment
  189.             rect.top = elements[index][0];
  190.             rect.bottom = rect.top + areaSize;
  191.             rect.right = rect.left + areaSize;
  192.             
  193.             RGBForeColor(&(theSnake->whatColor));
  194.             if(theSnake->whatStyle == kCooperativeThread)
  195.                 PaintRect(&rect);                    // Draw a rectangle, symbolizing we are Cooperative
  196.             else
  197.                 PaintOval(&rect);                    // Draw an oval, symbolizing we are Preemptive
  198.         }
  199.  
  200.         /*
  201.          *    Depending on the semaphore we are using, call the appropriate type
  202.          *  to release it.
  203.          */
  204. #if LLSNAKES
  205.         ReleaseLinkedListSemaphore(theLLSemaphore);
  206. #elif SIMPLESNAKES
  207.         ReleaseSimpleSemaphore( theSimpleSemaphore );
  208. #elif ARRAYSNAKES
  209.         ReleaseArraySemaphore( theArraySemaphore );
  210. #endif
  211.         YieldToAnyThread();
  212.     }
  213.     
  214. }    
  215.  
  216. /*
  217.  *  initSnakes()
  218.  *    
  219.  *  INPUT:    none
  220.  *  RETURN:    void
  221.  *
  222.  *    Creates a thread pool of 6 Cooperative and 6 Preemptive threads.
  223.  *  Aborts if failure.
  224.  */
  225. void initSnakes()
  226. {
  227.     OSErr             theError;
  228.     ThreadID        the1ID, the2ID;
  229.             
  230.     /*
  231.      * Start a critical section when creating threads, because if you don't, the minute you create 
  232.      * a preemptive thread, and it's in the ready state, it can preempt you.  So either create
  233.      * threads within a critical section, or create them all in the stopped state and wake them up
  234.      * or .... be creative.....
  235.      */
  236.     ThreadBeginCritical();
  237.     
  238.     theError = CreateThreadPool(kCooperativeThread, 6, 0);
  239.     if(theError != noErr)
  240.         myError("\pCreating cooperative threads.");
  241.  
  242.         
  243.     theError = CreateThreadPool(kPreemptiveThread, 6, 0);
  244.     if(theError != noErr)
  245.         myError("\pCreating preemptive threads.");
  246.  
  247.     
  248.      theError = NewThread(snake1.whatStyle, drawSnake, (void *) &snake1, 0, kUsePremadeThread, NULL, &the1ID);
  249.     if(theError != noErr)
  250.         myError("\pCreating Snake1.");    
  251.  
  252.  
  253.      theError = NewThread(snake2.whatStyle, drawSnake, (void *) &snake2, 0, kUsePremadeThread, NULL, &the2ID);
  254.     if(theError != noErr)
  255.         myError("\pCreating Snake2.");    
  256.  
  257.         
  258.      theError = NewThread(snake3.whatStyle, drawSnake, (void *) &snake3, 0, kUsePremadeThread, NULL, &the2ID);
  259.     if(theError != noErr)
  260.         myError("\pCreating Snake3.");    
  261.  
  262.  
  263.      theError = NewThread(snake4.whatStyle, drawSnake, (void *) &snake4, 0, kUsePremadeThread, NULL, &the2ID);
  264.     if(theError != noErr)
  265.         myError("\pCreating Snake4.");    
  266.  
  267.  
  268.      theError = NewThread(snake5.whatStyle, drawSnake, (void *) &snake5, 0, kUsePremadeThread, NULL, &the2ID);
  269.     if(theError != noErr)
  270.         myError("\pCreating Snake5.");
  271.     
  272.  
  273. #if LLSNAKES
  274.     if(CreateLinkedListSemaphore( &theLLSemaphore ) != noErr)
  275.         DebugStr("\pFailed to create the LinkedList Semaphore");
  276. #elif SIMPLESNAKES
  277.     if( CreateSimpleSemaphore( &theSimpleSemaphore ) != noErr)
  278.         DebugStr("\pFailed to create the Simple Semaphore");
  279. #elif ARRAYSNAKES
  280.     if( CreateArraySemaphore( 5, &theArraySemaphore) != noErr)
  281.         DebugStr("\pFailed to create the Array Semaphore");
  282. #endif
  283.  
  284.     ThreadEndCritical();
  285.  
  286. }
  287.  
  288.  
  289.